////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_EXPRESSION_H__
#define __WN_EXPRESSION_H__

#include "WNScripting/inc/WNParseNode.h"

enum WNExpressionType {
    eWNIdentifierExpression,
    eWNConstantExpression,
    eWNArithmeticAdd,
    eWNArithmeticSubtract,
    eWNArithmeticMultiply,
    eWNArithmeticMod,
    eWNArithmeticDivide,
    eWNArithmeticEquality,
    eWNReferenceTypeInitialization,
    eWNConstantStringInitialization,
    eWNArithmeticSquareBrackets,
    eWNFunctionCall,
    eWNStructAccess,
    eWNReferenceCreation,
    eWNArrayLength
};

enum WNExpressionConstantInt {
    eWNConstantIntExpression
};

enum WNExpressionConstantFloat {
    eWNConstantFloatExpression
};

enum WNExpressionConstantChar {
    eWNConstantCharExpression
};

enum WNExpressionConstantType {
    eWNConstantInt,
    eWNConstantFloat,
    eWNConstantChar
};

class WNDataType;
class WNExpressionList;

class WNExpression : public WNParseNode {
public:
    virtual ~WNExpression();
    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNIdentifierElement _identifier);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNS_INT_CONST _constVal,
                 WNExpressionConstantInt _constInt);
    
    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNS_CHAR_CONST _constVal,
                 WNExpressionConstantChar _constChar);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNS_FLOAT_CONST _constVal,
                 WNExpressionConstantFloat);

    //TODO: Merge ExpressionType with WNStaticArithmetic
    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNExpressionType _type,
                 WNExpression* _LHS,
                 WNExpression* _RHS);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNExpression* _LHS,
                 WNExpression* _RHS,
                 WNStaticPredicate _pred);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNDataType* _dataType,
                 WN_BOOL _heapAlloc);
    
    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNIdentifierElement _identifier,
                 WNExpressionList* _params);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNExpression* _LHS,
                 WNIdentifierElement _structIdentifier);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNDataType* _dataType,
                 WN_BOOL _heap,
                 std::vector<WNExpression*>* _exprList,
                 WN_BOOL _ignoreLastCreation);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNS_STRING_CONST _dataType,
                 WN_BOOL _heapAlloc);

    WNExpression(WN_SIZE_T _startLine,
                 WN_SIZE_T _endLine,
                 WN_SIZE_T _startChar,
                 WN_SIZE_T _endChar,
                 WNExpression* _expr,
                 WNExpressionType _type);

    WNTypeElement GetType();
    WN_BOOL ConstantFold(WNScriptingEngineData& _scriptingData);
    virtual llvm::Value* OptimizeAndGenerate(WNScriptingEngineData& _scriptingData, WNFunctionDecl* _functionDecl);
    virtual WN_BOOL ReportErrors();

private:
    //TODO make constVal not a pointer (we want to be able to specify floating point size)
    union {
        WNIdentifierElement mIdentifier;
        WNExpression* mLHS;
        WNDataType* mDataInitializer;
        WNS_STRING_CONST mStringInitializer;
        WN_CHAR mConstVal[WN_SCRIPTING_MAX_CONST_SIZE];
    } mFirstElement;

    union {
        WNExpression* mRHS;
        WNExpressionList* mExpressionList;
        WNIdentifierElement mIdentifier;
        std::vector<WNExpression*>* mArrayExpressions;
    } mSecondElement;

    WN_BOOL mHeapAlloc;
    WN_BOOL mFolded;
    WNExpressionConstantType mConstType;
    WNExpressionType mType;
    WNTypeElement mElementType;
    WNStaticPredicate mPredicate;
    WN_BOOL mSuppressLastCreation;
};

#endif // __WN_EXPRESSION_H__